package geppetto.cat.alignments;

import geppetto.cat.corpus.BilingualCorpus;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;

public class DynamicAlignmentSet extends AlignmentsSet{
	public static final int ALIGNMENTS_IN_MEM = 1000;

	protected String alignmentFile = "";
	protected int currentFilePosition = 0;
	protected BufferedReader alignmentReader;
	protected String alignmentType = "moses";
	byte sentenceSource;
	boolean reverse = false;
	BilingualCorpus corpus = new BilingualCorpus();
	
	public DynamicAlignmentSet(String alignmentFile, String alignmentType, byte sentenceSource, BilingualCorpus corpus) {
		super();
		this.alignmentFile = alignmentFile;
		this.alignmentType = alignmentType;
		this.sentenceSource = sentenceSource;
		this.corpus = corpus;
	}

	public static AlignmentsSet getAlignmentFromMoses(String file,
			byte sentenceSource, BilingualCorpus corpus) throws IOException {
		DynamicAlignmentSet set = new DynamicAlignmentSet(file, "moses", sentenceSource,corpus);		
		set.resetReader();
		System.out.println("Finish Building Alignments Set");
		return set;
	}
	
	public static AlignmentsSet getAlignmentFromPosterior(String file,
			byte sentenceSource, BilingualCorpus corpus) throws IOException {
		DynamicAlignmentSet set = new DynamicAlignmentSet(file, "posterior", sentenceSource,corpus);
		set.resetReader();
		System.out.println("Finish Building Alignments Set");
		return set;
	}

	@Override
	public void addAlignment(Alignment al) {
		System.out.println("cannot call this method(addAlignment) in this alignment set");
		System.exit(0);
		super.addAlignment(al);
	}

	@Override
	public Alignment get(int number) {
		if(number < currentFilePosition - ALIGNMENTS_IN_MEM){
			try {
				resetReader();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
				return null;
			} catch (IOException e) {
				e.printStackTrace();
				return null;
			}
		}
			while(number + ALIGNMENTS_IN_MEM > currentFilePosition && currentFilePosition < corpus.getNumSentences(sentenceSource)){
				try {
					readAlignment();					
				} catch (IOException e) {
					e.printStackTrace();
					return null;
				}
			}
		return _alignments.get(number - Math.max(currentFilePosition - ALIGNMENTS_IN_MEM, 0));
	}
	
	protected void readAlignment() throws IOException{
		Alignment al = null;
		if(alignmentType.equals("moses")){
			al = readMosesAlignment(alignmentReader, currentFilePosition, sentenceSource, corpus.getSourceSentenceLength(currentFilePosition, sentenceSource), corpus.getForeignSentenceLength(currentFilePosition, sentenceSource));
		}
		else{
			al = readPosteriorAlignment(alignmentReader, currentFilePosition, sentenceSource, corpus.getSourceSentenceLength(currentFilePosition, sentenceSource), corpus.getForeignSentenceLength(currentFilePosition, sentenceSource));
		}
		currentFilePosition++;
		if(reverse){
			al = al.reverse();
		}
		while(_alignments.size() >= ALIGNMENTS_IN_MEM){
			_alignments.remove(0);
		}
		_alignments.add(al);
	}
	
	protected void resetReader() throws FileNotFoundException, IOException{
		alignmentReader = getAlignmentFileReader(alignmentFile);
		currentFilePosition=0;
		_alignments = new ArrayList<Alignment>();
	}

	@Override
	public Alignment getAlignmentByPos(int pos) {
		System.out.println("cannot call this method(getAlignmentByPos) in this alignment set");
		System.exit(0);
		return super.getAlignmentByPos(pos);
	}

	@Override
	public ArrayList<Alignment> getAlignments() {
		System.out.println("cannot call this method(getAlignments) in this alignment set");
		System.exit(0);
		return super.getAlignments();
	}

	@Override
	public int numberOfAlignedPoints() {
		System.out.println("cannot call this method(numberOfAlignedPoints) in this alignment set");
		System.exit(0);
		return super.numberOfAlignedPoints();
	}

	@Override
	public int numberOfAlignedPoints(int type) {
		System.out.println("cannot call this method(numberOfAlignedPoints) in this alignment set");
		System.exit(0);
		return super.numberOfAlignedPoints(type);
	}

	@Override
	public int numberOfSourceUnaligned() {
		System.out.println("cannot call this method(numberOfSourceUnaligned) in this alignment set");
		System.exit(0);
		return super.numberOfSourceUnaligned();
	}

	@Override
	public void outputWithStatistics(BilingualCorpus corpus, PrintStream out,
			int maxNumber) throws UnsupportedEncodingException {
		System.out.println("cannot call this method in this alignment set");
		System.exit(0);
		super.outputWithStatistics(corpus, out, maxNumber);
	}

	@Override
	public void outputWithStatistics(BilingualCorpus corpus, PrintStream out)
			throws UnsupportedEncodingException {
		System.out.println("cannot call this method in this alignment set");
		System.exit(0);
		super.outputWithStatistics(corpus, out);
	}

	@Override
	public AlignmentsSet reverse() {
		DynamicAlignmentSet set = new DynamicAlignmentSet(alignmentFile, alignmentType, sentenceSource,corpus);		
		try {
			set.resetReader();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		set.setReverse(!reverse);
		return set;
	}

	@Override
	public int size() {
		System.out.println("cannot call this method(size)in this alignment set");
		System.exit(0);
		return super.size();
	}

	@Override
	public AlignmentsSet sortByAER(AlignmentsSet setGold) {
		System.out.println("cannot call this method in this alignment set");
		System.exit(0);
		return super.sortByAER(setGold);
	}

	@Override
	public AlignmentsSet[] splitBySentenceLen() {
		System.out.println("cannot call this method in this alignment set");
		System.exit(0);
		return super.splitBySentenceLen();
	}
	
	public void setReverse(boolean reverse){
		this.reverse = reverse;
	}
	
}
